package com.ytjj.qmyx.mall.service.thirdpay;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.upay.sdk.ConfigurationUtils;
import com.upay.sdk.FastJsonUtils;
import com.upay.sdk.entity.Payer;
import com.upay.sdk.entity.ProductDetail;
import com.upay.sdk.executer.ResultListenerAdpater;
import com.upay.sdk.onlinepay.builder.OrderBuilder;
import com.upay.sdk.onlinepay.builder.QueryBuilder;
import com.upay.sdk.onlinepay.builder.RefundBuilder;
import com.upay.sdk.onlinepay.executer.OnlinePayOrderExecuter;
import com.ytjj.common.exception.GlobalExceptionHandler;
import com.ytjj.common.service.RedisService;
import com.ytjj.common.utils.HttpClientUtil;
import com.ytjj.common.utils.IPUtil;
import com.ytjj.common.utils.TokenUtil;
import com.ytjj.common.utils.feishu.FeiShuUtil;
import com.ytjj.qmyx.mall.config.SupplyApiConfig;
import com.ytjj.qmyx.mall.constants.IsPayConstant;
import com.ytjj.qmyx.mall.enums.OrderPaySource;
import com.ytjj.qmyx.mall.enums.OrderPayTypeEnums;
import com.ytjj.qmyx.mall.enums.OrderStatusEnums;
import com.ytjj.qmyx.mall.enums.PayPayTypeEnums;
import com.ytjj.qmyx.mall.mapper.*;
import com.ytjj.qmyx.mall.model.*;
import com.ytjj.qmyx.mall.model.dto.WxPayDto;
import com.ytjj.qmyx.mall.model.request.UpdateOrderStatusRequest;
import com.ytjj.qmyx.mall.service.OrdersService;
import com.ytjj.qmyx.mall.service.ProductService;
import com.ytjj.qmyx.mall.service.WxService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.configuration.MapConfiguration;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("APP-UPAY")
@Slf4j
public class UpayService implements WxService<WxPayDto> {

    private static final String ENCRYPT_KEY = "encryptKey";
    private static final String MERCHANT_ID = "merchantId";

    @Resource
    private OrdersDao ordersDao;

    @Resource
    private OrdersPayMapper ordersPayMapper;

    @Resource
    private OrdersMapper ordersMapper;
    @Resource
    private OrdersInfoMapper ordersInfoMapper;

    @Resource
    private RedisService redisService;
    @Resource
    private ProductService productService;

    @Resource
    private OrdersService ordersService;

    @Resource
    private ReturnGoodsDao returnGoodsDao;
    @Resource
    private SupplyApiConfig supplyApiConfig;



    /**
     * 初始化 sprin 启动就加载
     */
    @PostConstruct
    public void init() {
        PayConfig payConfig = ordersDao.getPayConfigByCompany("upay", "H5", "upay");
        if (payConfig!=null){
            Map<String, Object> map = new HashMap<>();
            map.put("http.content.type.v3", "application/vnd.5upay-v3.0+json");
            map.put("http.content.type.v4", "application/vnd.5upay-v4.0+json");
            map.put("891693175.client.private.key.path", payConfig.getPrivateKeyPath());
            map.put("891693175.client.private.key.password", payConfig.getWxKey());
            map.put("onlinepay.order.url", "https://apis.5upay.com/onlinePay/order");
            map.put("onlinepay.refund.url", "https://apis.5upay.com/onlinePay/refund");
            map.put("onlinepay.query.url", "https://apis.5upay.com/onlinePay/query");
            map.put("onlinepay.refund.query.url", "https://apis.5upay.com/onlinePay/refundQuery");
            map.put("onlinepay.cancelOrder.url", "https://apis.5upay.com/onlinePay/cancelOrder");

            ConfigurationUtils.setConfigSource(new MapConfiguration(map));
            System.setProperty("jdk.tls.disabledAlgorithms","");
        }
    }

    @Override
    public Map<String, String> doUnifiedOrder(WxPayDto wxAppPayDto) throws Exception{
        String ip;
        try {
            ip = IPUtil.getIpAddress(TokenUtil.getRequest());
        } catch (Exception e) {
            log.error("ip获取报错:",e);
            ip = "0.0.0.0";
        }

        PayConfig payConfig = ordersDao.getPayConfigByCompany("upay", "H5", "upay");
        String returnUrl =payConfig.getRedirectUrl();
        returnUrl = returnUrl + "?orderNo="+wxAppPayDto.getOrderNo()+"&token="+wxAppPayDto.getToken();

        OrderBuilder builder = new OrderBuilder(payConfig.getSubMchId());
        builder.setRequestId(wxAppPayDto.getResOrderNo())
                .setOrderAmount(wxAppPayDto.getRealTotalMoney())
                .setOrderCurrency("CNY")
                .setNotifyUrl(payConfig.getNotifyUrl())
                .setCallbackUrl(returnUrl)
                .setRemark("")
                .setPaymentModeCode("ALIPAY-WAP-P2P")
                .setClientIp(ip);

        builder.setAppId(payConfig.getAppid());
        builder.setOpenId(wxAppPayDto.getOpenid());
        builder.setNeedOpenLink("1");
        //报备序列号（可咨询商务经理）
//        builder.setReportSerialNo("89223946901001");
        //服务商在首信易系统的唯一id，可在商户后台查看
        builder.setPartnerId(payConfig.getMchId());

        //商品信息
        ProductDetail productDetail = new ProductDetail();
        productDetail.setName(wxAppPayDto.getBody());
        productDetail.setQuantity(1L);
        productDetail.setAmount(Long.parseLong(wxAppPayDto.getRealTotalMoney()));
        builder.addProductDetail(productDetail);


        builder.setPayer(new Payer());

        final Map<String, String>[] param = new Map[]{new HashMap<>()};
        try {
            OnlinePayOrderExecuter executer = new OnlinePayOrderExecuter();
            System.setProperty("https.protocols", "TLSv1.2,TLSv1.1,SSLv3");
            executer.bothOrder(builder, new ResultListenerAdpater() {
                @Override
                public void failure(JSONObject jsonObject) {
                    log.info("failure jsonObject:{}",jsonObject);
                }

                /**
                 * 提交成功，不代表支付成功
                 */
                @Override
                public void success(JSONObject jsonObject) {
                    log.info("success jsonObject:{}",jsonObject);
                    if (jsonObject.get("status") != null && "SUCCESS".equals(jsonObject.get("status"))) {
                        String jsString = (String) jsonObject.get("jsString");
                        param[0] = JSON.parseObject(jsString, Map.class);
                        param[0].put("payConfigId", String.valueOf(payConfig.getId()));

                    }
                }

                @Override
                public void pending(JSONObject jsonObject) {
                    super.pending(jsonObject);
                }

                @Override
                public void processing(JSONObject jsonObject) {
                    super.processing(jsonObject);
                }

                @Override
                public void redirect(JSONObject jsonObject, String redirectUrl) throws IOException {
                    log.info("redirectUrl:[" + redirectUrl + "]");
                    param[0].put("redirectUrl", redirectUrl);
                    param[0].put("payConfigId", String.valueOf(payConfig.getId()));
                }


            });
        } catch (Exception e) {
            log.error("upay拉支付报错,{}",e);
            FeiShuUtil.sendMsg(String.format("upay拉支付报错,%s",e.getMessage()));
        }

        return param[0];
    }

    @Override
    public Map<String, String> doUnifiedRechargeOrder(WxPayDto wxPayDto) throws Exception {
        return null;
    }

    @Override
    public Map<String, String> wxOrderQuery(String resOrderNo) throws Exception {
        PayConfig payConfig = ordersDao.getPayConfigByCompany("upay", "H5", "upay");

        QueryBuilder builder = new QueryBuilder(payConfig.getSubMchId());
        builder.setRequestId(resOrderNo);
        builder.setPartnerId(payConfig.getMchId());

        OnlinePayOrderExecuter executer = new OnlinePayOrderExecuter();
        try {
            executer.bothQuery(builder, new ResultListenerAdpater() {
                @Override
                public void success(JSONObject jsonObject) {
                    log.info("处理成功,{}",jsonObject.toJSONString());
                    //业务处理
                    updateOrderInfo(jsonObject);
                }

                @Override
                public void failure(JSONObject jsonObject) {
                    log.info("处理失败,{}",jsonObject.toJSONString());
                }

                @Override
                public void pending(JSONObject jsonObject) {
                    log.info("待处理,{}",jsonObject.toJSONString());
                }
            });
        } catch (Exception e) {
            log.error("{}",e);
        }
        return null;
    }

    @Override
    public Map<String, String> wxPhoneChargesQuery(String resOrderNo) throws Exception {
        return null;
    }

    @Override
    public Map refundOrders(String outTradeNo, String outRefundNo, Integer totalFee, Integer refundFee, String refundDesc) throws Exception {
        return null;
    }

    @Override
    public Map refundRecharge(String outTradeNo, String outRefundNo, Integer totalFee, Integer refundFee, String refundDesc) throws Exception {
        return null;
    }

    public void updateOrderInfo(JSONObject jsonObject){
        String status = (String) jsonObject.get("status");
        String requestId = (String) jsonObject.get("requestId");
        OrdersPay pay = ordersDao.queryOrdersPayByResOrderNo(requestId);
        if ("SUCCESS".equals(status)){
            String serialNumber = (String) jsonObject.get("serialNumber");
            String orderAmount = (String) jsonObject.get("orderAmount");
            String completeDateTime = (String) jsonObject.get("completeDateTime");
            if (StringUtils.isNotBlank(requestId)){
                if (null == pay || (pay.getPayType().byteValue() == PayPayTypeEnums.SUCCEED.getType() && pay.getTransactionId()!=null)) {
                    return;
                }
                // 更新支付订单信息
                if (StringUtils.isNotBlank(orderAmount)) {
                    pay.setTotalFee(Integer.valueOf(orderAmount));
                } else {
                    if (null != pay.getAmount()) {
                        BigDecimal big_total_fee = pay.getAmount().multiply(new BigDecimal(100));
                        pay.setTotalFee(big_total_fee.intValue());
                    }
                }
                pay.setResText(jsonObject.toString());
                pay.setPayTime(completeDateTime);
                pay.setPayType(PayPayTypeEnums.SUCCEED.getType());
                pay.setUpdateTime(new Date());
                pay.setTransactionId(serialNumber);
                ordersPayMapper.updateByPrimaryKeyWithBLOBs(pay);

                // 更新订单信息
                Orders orders = new Orders();
                orders.setPayType(OrderPayTypeEnums.online_pay.name());
                orders.setPaySource(OrderPaySource.alipay.name());
                orders.setIsPay(IsPayConstant.YES);
                orders.setOrderStatus(OrderStatusEnums.UNSHIPPED.getValue());
                orders.setPayTime(new Date());
                orders.setTradeNo(pay.getResOrderNo());
                OrdersExample example = new OrdersExample();
                example.createCriteria()
                        .andOrderNoEqualTo(pay.getOrderNo());
                ordersMapper.updateByExampleSelective(orders, example);
                // 获取订单信息
                Orders order = ordersDao.queryOrdersByOrderNo(pay.getOrderNo());

                // 获取订单明细
                OrdersInfoExample ordersInfoExample = new OrdersInfoExample();
                ordersInfoExample.createCriteria().andOrderIdEqualTo(order.getId());
                List<OrdersInfo> ordersInfoList = ordersInfoMapper.selectByExample(ordersInfoExample);
                ordersInfoList.stream()
                        .forEach(item -> {
                            String tokenUser = redisService.get(order.getH5Token());

                            // 修改订单详情状态
                            OrdersInfo ordersInfo = new OrdersInfo();
                            ordersInfo.setId(item.getId());
                            ordersInfo.setOrderinfoStatus(OrderStatusEnums.UNSHIPPED.getValue());
                            ordersInfoMapper.updateByPrimaryKeySelective(ordersInfo);
                            try {
                                // 商品 减库存 加销量 店家加销量
                                productService.sellAfter(item.getProductId(), item.getProductSpecId(), item.getProductSum(), item.getProductPrice(),
                                        item.getIsWalletPay(),tokenUser, item.getIsDirectbuy(), item.getActivityType(), item.getActivityMax(), order.getUserId());
                            } catch (Exception e) {
                                log.error(GlobalExceptionHandler.getExceptionToString(e));
                                log.error("减库存发生异常 订单id :{}", item.getId());
                            }

                        });
                //扣减库存
                try {
                    ordersService.subStock(order.getId());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }else{
            // 更新支付订单信息
            pay.setPayType(PayPayTypeEnums.FAIL.getType());
            pay.setUpdateTime(new Date());
            ordersPayMapper.updateByPrimaryKeyWithBLOBs(pay);
        }

    }

    public int refund(String transactionId,String refundNo,String amount){
        PayConfig payConfig = ordersDao.getPayConfigByCompany("upay", "H5", "upay");

        RefundBuilder builder = new RefundBuilder(payConfig.getSubMchId());
        builder.setRequestId(refundNo)
                .setAmount(amount)
                .setOrderId(transactionId)
                .setRemark("平台退款")
                .setNotifyUrl(payConfig.getRefundNotifyUrl());

        //服务商在首信易系统的唯一id，可在商户后台查看
        builder.setPartnerId(payConfig.getMchId());

        OnlinePayOrderExecuter executer = new OnlinePayOrderExecuter();

        final int[] flag = {0};
        try {
            executer.bothRefund(builder, new ResultListenerAdpater() {
                @Override
                public void success(JSONObject jsonObject) {
                    log.info("refund 处理成功,jsonObject:{}",jsonObject);
                    String status = (String) jsonObject.getString("status");
                    if ("SUCCESS".equals(status)){
                        flag[0] =1;
                    }
                }

                @Override
                public void failure(JSONObject jsonObject) {
                    log.info("refund 处理失败,jsonObject:{}",jsonObject.toJSONString());
                }

                @Override
                public void pending(JSONObject jsonObject) {
                    log.info("refund 处理中,jsonObject:{}",jsonObject.toJSONString());
                }
            });
        } catch (Exception e) {
            log.error("首信易调用退款接口失败,{}",e);
            FeiShuUtil.sendMsg(String.format("首信易调用退款接口失败,%s",e.getMessage()));
        }
        return flag[0];
    }

    public void notifyUpayRefund(HttpServletRequest req){
        try {
            OnlinePayOrderExecuter executer = new OnlinePayOrderExecuter();
            JSONObject json = FastJsonUtils.convert(req.getInputStream());
            String encryptKey = req.getHeader(ENCRYPT_KEY);
            String merchantId = req.getHeader(MERCHANT_ID);
            json.put(ENCRYPT_KEY, encryptKey);
            json.put(MERCHANT_ID, merchantId);

            log.info("encryptKey : {},merchantId : {}", encryptKey, merchantId);
            executer.bothCipherCallback(json, new ResultListenerAdpater() {

                @Override
                public void success(JSONObject jsonObject) {
                    log.info("首信易退款回调退款成功！");
                    log.info(jsonObject.toJSONString());
                    String status = (String) jsonObject.get("status");
                    String requestId = (String) jsonObject.get("requestId");
                    if ("SUCCESS".equals(status)){
                        updateAdminOrderInfo(requestId);
                        // 退款表状态更新
                        ordersDao.updateOrderRefundStatus(2,requestId,jsonObject.toJSONString());
                    }else {
                        // 退款表状态更新
                        ordersDao.updateOrderRefundStatus(3,requestId,jsonObject.toJSONString());
                    }
                }

                @Override
                public void failure(JSONObject jsonObject) {
                    log.info("首信易退款回调退款失败！");
                    log.info(jsonObject.toJSONString());
                    String requestId = (String) jsonObject.get("requestId");
                    // 退款表状态更新
                    ordersDao.updateOrderRefundStatus(3,requestId,jsonObject.toJSONString());
                }
            });
        } catch (Exception e) {
            log.error("首信易退款回调通知报错,{}",e);
            FeiShuUtil.sendMsg(String.format("首信易退款回调通知报错,%s",e.getMessage()));
        }
    }

    public void updateAdminOrderInfo(String requestId){
        Integer orderInfoId = ordersDao.findOrderInfoIdByRefund(Integer.parseInt(requestId));
        if (orderInfoId!=null){
            ReturnGoods returnGoods = ordersDao.selectReturnGoodsByWaitBackAmount(orderInfoId);
            if (returnGoods!=null){
                // 同步退货管理中的退货状态
                ReturnGoods returnGoodsInfo = returnGoodsDao.findByServiceNo(returnGoods.getServiceNo());
                if (returnGoodsInfo != null) {
                    returnGoodsDao.returnGoodsSuccess(returnGoodsInfo.getId());
                }else {
                    return;
                }
                //交易关闭原因
                String closeRemarks = getCloseRemarks(returnGoodsInfo);

                //退款成功主子订单为已关闭
                OrdersInfo ordersInfo = ordersInfoMapper.selectByPrimaryKey(returnGoodsInfo.getOrdersInfoId());
                ordersDao.updateStatusByOid(returnGoodsInfo.getOrdersInfoId(), "4", closeRemarks);
                ordersDao.updateOrderStatusById(ordersInfo.getOrderId(),"4",returnGoods.getServiceNo());

                // 原路返回页中订单详情状态改为已关闭
                ordersDao.modifiedReturnRegister(returnGoodsInfo.getOrdersInfoId());

                //更新供应链订单状态  销售端调用 （当销售端退款后，需要修改订单状态）
                UpdateOrderStatusRequest updateOrderStatusRequest = new UpdateOrderStatusRequest();
                updateOrderStatusRequest.setChildOrderNo(ordersInfo.getChildOrderNo());
                updateOrderStatusRequest.setShopId(supplyApiConfig.getShopId());
                updateOrderStatusRequest.setOrderStatus(4);
                String json = JSON.toJSONString(updateOrderStatusRequest);
                HttpClientUtil.doPostJson(supplyApiConfig.getUrl() + "/order/updateOrderStatus", json, supplyApiConfig.getHeadsMap());

                //更新供应链售后信息
                YxReturnGoods yxReturnGoodsRequest = new YxReturnGoods();
                yxReturnGoodsRequest.setServiceNo(returnGoods.getServiceNo());
                yxReturnGoodsRequest.setStatus(9);

                yxReturnGoodsRequest.setShopId(supplyApiConfig.getShopId());
                String json2 = JSON.toJSONString(yxReturnGoodsRequest);
                HttpClientUtil.doPostJson(supplyApiConfig.getUrl() + "/returnGoods/updateReturnGoods", json2, supplyApiConfig.getHeadsMap());

//        if (null != returnGoodsInfo.getAfterType() && returnGoodsInfo.getAfterType() == 1) {
//            //售后类型为退款 把库存加回来
//            Product product = productMapper.selectByPrimaryKey(ordersInfo.getProductId());
//            subAndAddStock(ordersInfo.getChildOrderNo(), ordersInfo.getProductSum(), product.getIsZeroProduct(), "add");
//        }

            }
        }


    }

    public String getCloseRemarks(ReturnGoods returnGoodsInfo) {
        String closeRemarks = "";
        if (returnGoodsInfo.getAfterType() == 1) {
            closeRemarks = "订单已申请退款";
        } else if (returnGoodsInfo.getAfterType() == 2) {
            closeRemarks = "订单已申请退货退款";
        } else if (returnGoodsInfo.getAfterType() == 3) {
            closeRemarks = "订单已申请仅退款";
        }
        return closeRemarks;
    }

    public void notifyUpay(HttpServletRequest req){
        OnlinePayOrderExecuter executer = new OnlinePayOrderExecuter();

        try {
            JSONObject json = FastJsonUtils.convert(req.getInputStream());
            json.put(ENCRYPT_KEY, req.getHeader(ENCRYPT_KEY));
            json.put(MERCHANT_ID, req.getHeader(MERCHANT_ID));
            executer.bothCipherCallback(json, new ResultListenerAdpater() {
                @Override
                public void success(JSONObject jsonObject) {
                    log.info("支付成功,json:{}",jsonObject);
                    //业务处理
                    updateOrderInfo(jsonObject);

                }

                @Override
                public void failure(JSONObject jsonObject) {
                    log.info("支付失败,json:{}",jsonObject);
                    FeiShuUtil.sendMsg(String.format("upay回调报错,%s",jsonObject.toJSONString()));
                }
            });
        } catch (Exception e) {
            log.error("upay回调报错,{}",e);
//            FeiShuUtil.sendMsg(String.format("upay回调报错,%s",e.getMessage()));
        }
    }

    public static void main(String[] args) {

        Map<String, Object> map = new HashMap<>();
        map.put("http.content.type.v3", "application/vnd.5upay-v3.0+json");
        map.put("http.content.type.v4", "application/vnd.5upay-v4.0+json");
        map.put("891693175.client.private.key.path", "d:\\hyd.pfx");
        map.put("891693175.client.private.key.password", "xxxx");
        map.put("onlinepay.order.url", "https://apis.5upay.com/onlinePay/order");
        map.put("onlinepay.refund.url", "https://apis.5upay.com/onlinePay/refund");

        ConfigurationUtils.setConfigSource(new MapConfiguration(map));
        System.setProperty("jdk.tls.disabledAlgorithms","");

//        doUnifiedOrder();
//        refund();
    }
}
